#include "mainwindow.h"
#include "./ui_mainwindow.h"

// 按钮 使能 样式
QString MainWindow::styleBtnEnableT = "QPushButton {"
                                      "border-radius: 5px;"        // 设置圆角半径为
                                      "border: 1px solid #DADADA;" // 设置边框颜色
                                      "background-color: #FDFDFD;" // 背景颜色
                                      "}"
                                      "QPushButton:hover {"
                                      "background-color: #F0F0F0;"
                                      "}"
                                      "QPushButton:pressed  {"
                                      "background-color: #E0E0E0;"
                                      "}";
// 按钮 不使能 样式
QString MainWindow::styleBtnEnableF = "QPushButton {"
                                      "border-radius: 5px;"        // 设置圆角半径为
                                      "border: 1px solid #DADADA;" // 设置边框颜色
                                      "background-color: #E0E0E0;" // 背景颜色
                                      "}"
                                      "QPushButton:hover {"
                                      "background-color: #F0F0F0;"
                                      "}"
                                      "QPushButton:pressed  {"
                                      "background-color: #E0E0E0;"
                                      "}";

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 置顶
    setWindowFlag(Qt::WindowStaysOnTopHint);

    currFileNameRaw.clear();
    currFileNameWav.clear();
    audioSamples.clear();

    // 初始化文件路径为当前路径
    filePath = QDir::currentPath();
    // 显示文件路径
    ui->lineEdit->setText(filePath);

    // 设置所有按钮样式
    ui->widget_2->setStyleSheet(styleBtnEnableT);

    // 选择文件目录
    connect(ui->btn_choose, &QPushButton::clicked, this, [&]()
    {
        QString str = QFileDialog::getExistingDirectory(this, "选择文件目录", filePath);
        if (!str.isEmpty())
        {
            filePath = str;
            ui->lineEdit->setText(filePath);
        }
    });

    // 打开对应文件夹
    connect(ui->btn_open, &QPushButton::clicked, this, [&]()
    {
        QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
    });

    // 选择采样率
    connect(ui->comboBox_switch, &QComboBox::currentIndexChanged, this, [&](int index)
    {
        switch (index)
        {
        case 0:
            audioSampleRate = 8000;
            break;
        case 1:
            audioSampleRate = 16000;
            break;
        default:
            audioSampleRate = 8000;
            break;
        }
        qDebug() << index;
    });

    // 开始录音
    connect(ui->btn_start, &QPushButton::clicked, this, &MainWindow::recordAudio);

    // 删除录音按钮
    ui->btn_delete->setEnabled(false);
    ui->btn_delete->setStyleSheet(styleBtnEnableF);
    connect(ui->btn_delete, &QPushButton::clicked, this, [&]()
    {
        // 删除当前的录音文件
        QFile file(currFileNameWav);
        if (file.exists())
        {
            // 清空当前数据，重新画图
            audioSamples.clear();
            ui->waveform->setAudioSamples(audioSamples, 0);
            file.remove();
        }
        else
            QMessageBox::warning(this, "警告", "文件不存在:" + currFileNameWav, QMessageBox::Ok);

        ui->btn_delete->setEnabled(false);
        ui->btn_delete->setStyleSheet(styleBtnEnableF);
    });
}

// 录制音频
void MainWindow::recordAudio()
{
    // 暂时不使能按钮
    ui->btn_start->setEnabled(false);
    ui->btn_start->setStyleSheet(styleBtnEnableF);

    // 构造存储路径以及文件名
    QDir dir(filePath);
    labelName = ui->lineEdit_label->text();
    if (!isFileNameValid(labelName))
    {
        QMessageBox::warning(this, "警告", "文件名无效！只能包含数字、字母、短横线、下划线。", QMessageBox::Ok);
        // 使能按钮
        ui->btn_start->setEnabled(true);
        ui->btn_start->setStyleSheet(styleBtnEnableT);
        return;
    }

    if (!dir.exists(labelName))
        dir.mkdir(labelName);
    QString folderPath = dir.absoluteFilePath(labelName);
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmsszzz");
    QString fileName = QString("%1/%2_%3.raw").arg(folderPath, labelName, timestamp);
    currFileNameRaw = fileName;
    currFileNameWav = fileName.replace(".raw", ".wav");

    // 写录音文件
    destinationFile.setFileName(currFileNameRaw);
    destinationFile.open(QIODevice::WriteOnly | QIODevice::Truncate);

    QAudioFormat format;
    format.setSampleRate(audioSampleRate);       // 采样率
    format.setChannelCount(1);                   // 单通道
    format.setSampleFormat(QAudioFormat::Int16); // 十六位

    QAudioDevice info = QMediaDevices::defaultAudioInput();
    if (!info.isFormatSupported(format))
    {
        // qWarning() << "Default format not supported, trying to use the nearest.";
    }

    audio = new QAudioSource(format, this);
    // connect(audio, &QAudioSource::stateChanged, this, &MainWindow::handleStateChanged);

    QTimer::singleShot(1050, this, &MainWindow::stopRecording);
    audio->start(&destinationFile);
    // Records audio for 1000ms
}

void MainWindow::handleStateChanged(QAudio::State newState)
{
    switch (newState)
    {
    case QAudio::StoppedState:
        if (audio->error() != QAudio::NoError)
        {
            // Error handling
            qWarning() << "An error occurred during recording" << audio->error();
        }
        else
        {
            // Finished recording
            qInfo() << "Recording successfully completed;";
        }
        break;

    case QAudio::ActiveState:
        // Started recording - read from IO device
        break;

    default:
        // ... other cases as appropriate
        break;
    }
}

void MainWindow::stopRecording()
{
    audio->stop();
    destinationFile.close();
    delete audio;
    audio = nullptr;

    qInfo() << "Recording successfully completed;";

    // 加载raw文件，绘图；保存wav文件
    saveWavFile();

    // 使能开始按钮
    ui->btn_start->setEnabled(true);
    ui->btn_start->setStyleSheet(styleBtnEnableT);

    // 使能删除按钮
    ui->btn_delete->setEnabled(true);
    ui->btn_delete->setStyleSheet(styleBtnEnableT);
}

// 保存wav文件
void MainWindow::saveWavFile()
{
    QFile rawFile(currFileNameRaw);
    if (!rawFile.open(QIODevice::ReadOnly))
    {
        qWarning() << "Unable to open raw file for reading";
        return;
    }

    QByteArray rawData = rawFile.readAll();
    rawFile.close();

    QFile wavFile(currFileNameWav);
    if (!wavFile.open(QIODevice::WriteOnly))
    {
        qWarning() << "Unable to open wav file for writing";
        return;
    }

    // 加载原始数据，画图
    audioSamples.clear();
    // 处理数据，修改为一秒的数据量
    int toNum = audioSampleRate - rawData.size() / sizeof(qint16);
    if (toNum > 0)
        rawData.append(QByteArray(toNum * sizeof(qint16), 0));
    else if (toNum < 0)
        rawData = rawData.mid(0, audioSampleRate * sizeof(qint16));

    // 转换为16进制数据
    const qint16 *dataPtr = reinterpret_cast<const qint16 *>(rawData.constData());
    int numSamples = rawData.size() / sizeof(qint16);
    for (int i = 0; i < numSamples; ++i)
        audioSamples.append(dataPtr[i]);
    // 画图
    ui->waveform->setAudioSamples(audioSamples, toNum);

    QDataStream out(&wavFile);
    out.setByteOrder(QDataStream::LittleEndian);

    // Write WAV header
    qint32 fileSize = rawData.size() + 36;
    qint32 dataSize = rawData.size();
    qint16 format = 1;                   // PCM format
    qint16 channels = 1;                 // 单通道
    qint32 sampleRate = audioSampleRate; // 采样率
    qint16 bitsPerSample = 16;           // 位宽
    qint16 blockAlign = channels * (bitsPerSample / 8);
    qint32 byteRate = sampleRate * blockAlign;

    out.writeRawData("RIFF", 4);
    out << fileSize;
    out.writeRawData("WAVE", 4);
    out.writeRawData("fmt ", 4);
    out << qint32(16); // Subchunk1Size for PCM
    out << format;
    out << channels;
    out << sampleRate;
    out << byteRate;
    out << blockAlign;
    out << bitsPerSample;
    out.writeRawData("data", 4);
    out << dataSize;

    // Write raw data
    out.writeRawData(rawData.constData(), rawData.size());

    wavFile.close();
    rawFile.remove();
    qDebug() << "WAV file saved:" << currFileNameWav << "\tsize:" << dataSize << "bytes";
}

// 判断文件名是否有效，只能包含字母、数字、下划线和短横线
bool MainWindow::isFileNameValid(const QString &fileName)
{
    static QRegularExpression regex("^[a-zA-Z0-9_-]+$");
    return regex.match(fileName).hasMatch();
}

MainWindow::~MainWindow()
{
    delete ui;
}
